package modelo;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.Observable;

public class Venta extends Observable implements IVenta  {
	private enum UltimoLineItem { OFERTA, PRODUCTO}
	private List<LineItemProducto> items;
	private List<LineItemOferta> ofertasAplicadas;
	private LineItemFactory lineItemFactory;
	private OfertasRepository ofertas;
	private UltimoLineItem ultimoLineItem;
	private double descuentoAlTotalDeLaVenta;
	private String detalleOfertaTotalVenta;
	private String formaDePago;
	private Calendar fechaVenta;
	int nroCaja;
	
	public List<LineItemProducto> getProductos() {
		return Collections.unmodifiableList(items);
	}
	
	public Venta(OfertasRepository ofertas, Calendar fechaVenta, int nroCaja) {
		this.items = new ArrayList<LineItemProducto>();
		this.ofertasAplicadas = new ArrayList<LineItemOferta>();
		this.lineItemFactory = new LineItemFactory();
		this.ofertas = ofertas;
		this.descuentoAlTotalDeLaVenta = 0;
		this.detalleOfertaTotalVenta = "";
		this.fechaVenta = fechaVenta;
		this.formaDePago = "";
		this.nroCaja = nroCaja;
	}	
	
	@Override
	public void cobrar(String medioDePago) {
		this.formaDePago = medioDePago;
		ofertas.aplicarOfertas(this);
		addOferta(detalleOfertaTotalVenta, 1, getTotal() * descuentoAlTotalDeLaVenta);
	}
	
	@Override
	public double getTotal() {
		return getTotalSinDescuentos() - getTotalDescuentos();
	}
	
	@Override
	public double getTotalDescuentos() {
		int total = 0;
		for (LineItem i : ofertasAplicadas) {
			total += i.montoTotal();
		}
		return total;
	}

	@Override
	public double getTotalSinDescuentos() {
		int total = 0;
		for(LineItem i : items) {
			total += i.montoTotal();
		}
		return total;
	}	

	public List<LineItemOferta> getOfertasAplicadas()
	{
		return this.ofertasAplicadas;
	}
	
	@Override
	public void addProducto(Producto producto, int cantidad) {
		LineItemProducto item = lineItemFactory.lineItemProducto(producto, cantidad);		
		items.add(item);
		ultimoLineItem = UltimoLineItem.PRODUCTO;
		setChanged();
		notifyObservers();
		ofertas.aplicarOfertas(this);
	}
	
	@Override
	public void addOferta(String detalle, int cantidad, double montoUnitario) {
		LineItemOferta lineItemOferta = lineItemFactory.lineItemOferta(detalle, cantidad, montoUnitario);
		ofertasAplicadas.add(lineItemOferta);
		ultimoLineItem = UltimoLineItem.OFERTA;
		setChanged();
		notifyObservers();
	}

	@Override
	public boolean tieneDeUnTipoDeProducto(Producto producto, int cantidad) {		
		for (LineItemProducto lineItem : items) {
			if (lineItem.getIdProducto() == producto.getId()) {
				if (lineItem.getCantidad() - lineItem.getProductosConOfertasPorProductoAplicadas() >= cantidad)
					return true;
			}		
		}
		return false;
	}

	@Override
	public String getMedioDePago() {
		return formaDePago;
	}

	@Override
	public boolean hasCategoria(String categoria, int cantidad) {
		for (LineItemProducto lineItem : items) {
			if ((lineItem.getCategoriaProducto() == categoria) &&
				(lineItem.getCantidad() - lineItem.getProductosConOfertasPorCategoriaOMarcaAplicadas() >= cantidad))
					return true;	
		}
		return false;
	}

	@Override
	public Calendar getFecha() {
		return fechaVenta;
	}

	@Override
	public boolean hasMarca(String marca) {
		for (LineItemProducto lineItem : items) {
			if ((lineItem.getMarcaProducto() == marca) &&
				(lineItem.getCantidad() - lineItem.getProductosConOfertasPorCategoriaOMarcaAplicadas() > 0))
					return true;	
		}
		return false;
	}

	@Override
	public void aplicarDescuentoAProducto(Producto producto, int cantidad,
			double descuento, String detalleOferta) {
		addOferta(detalleOferta, cantidad, producto.getPrecio() * descuento);	
	}

	@Override
	public void aplicarDescuentoPorCategoria(String categoria,
			List<Producto> excepciones, double descuento, String detalleOferta) {
		for (LineItemProducto lineItem : items) {
			int cantidad = lineItem.getCantidad() - lineItem.getProductosConOfertasPorCategoriaOMarcaAplicadas();
			if ((lineItem.getCategoriaProducto() == categoria) && (cantidad > 0)) {
				boolean noEstaEnLasExcepciones = true;
				if (excepciones != null)
				{
					for (Producto p : excepciones) {
						if (p.getId() == lineItem.getIdProducto()) {
							noEstaEnLasExcepciones = false;
							break;
						}
					}
				}
				if (noEstaEnLasExcepciones) {
					lineItem.setProductosConOfertasPorCategoriaOMarcaAplicadas(lineItem.getCantidad());
					addOferta(detalleOferta, cantidad, lineItem.montoUnitario() * descuento);
				}
			}			
		}		
				
	}

	@Override
	public void aplicarDescuentoPorMarca(String marca,
			ArrayList<Producto> excepciones, double descuento, String detalleOferta) {
		for (LineItemProducto lineItem : items) {
			int cantidad = lineItem.getCantidad() - lineItem.getProductosConOfertasPorCategoriaOMarcaAplicadas();
			if ((lineItem.getMarcaProducto() == marca) && (cantidad > 0)) {
				boolean noEstaEnLasExcepciones = true;
				for (Producto p : excepciones) {
					if (p.getId() == lineItem.getIdProducto()) {
						noEstaEnLasExcepciones = false;
						break;
					}
				}
				if (noEstaEnLasExcepciones) {
					lineItem.setProductosConOfertasPorCategoriaOMarcaAplicadas(lineItem.getCantidad());
					addOferta(detalleOferta, cantidad, lineItem.montoUnitario() * descuento);
				}
			}			
		}		
	}

	@Override
	public void aplicarDescuentoAlTotal(double descuento, String detalleOferta) {
		if (descuento > descuentoAlTotalDeLaVenta) {
			descuentoAlTotalDeLaVenta = descuento;
			detalleOfertaTotalVenta = detalleOferta;
		}
		
	}

	@Override
	public void aplicarOfertaAProducto(Producto producto, int cantidad) {
		for (LineItemProducto lineItem : items) {
			if (lineItem.getIdProducto() == producto.getId()) {
				lineItem.setProductosConOfertasPorProductoAplicadas(lineItem.getProductosConOfertasPorProductoAplicadas() + cantidad);
				break;
			}			
		}		
	}

	@Override
	public LineItem getUltimoLineItem() {
		if (ultimoLineItem == UltimoLineItem.PRODUCTO)
			return getUltimoLineItemProducto();
		else
			return getUltimoLineItemOferta();
	}

	private LineItem getUltimoLineItemOferta() {
		return ofertasAplicadas.get(ofertasAplicadas.size() - 1);
	}

	private LineItem getUltimoLineItemProducto() {
		return items.get(items.size() - 1);
	}

	@Override
	public int getCajaNro() {
		return nroCaja;
	}


}
